package security.Authentication.UserPass;

import security.Authentication.Base.AuthenticationHandler;
import security.Authentication.Base.AuthenticationRequest;
import security.Authentication.Base.IdentifiedUser;
import security.Authentication.Base.UnknownUser;
import security.Authentication.Base.User;
import security.Authentication.StaticData.StaticUserPassInfo;
import security.Authorization.Base.AuthorizationLevel;

/**
 * An authentication handler that accepts a user with user name and password
 * @author Andreas Carmvall
 */
public class UserPassHandler extends AuthenticationHandler {

	@Override
	public User handleRequest(AuthenticationRequest request) {
		if (request instanceof UserPassRequest) {
			UserPassRequest userPassRequest = (UserPassRequest)request;
			String userName = userPassRequest.getUserName();
			String password = userPassRequest.getPassword();
			AuthorizationLevel level;
			
			// Check the user information values boundaries
			if (!checkUserName(userName)) {
				return new UnknownUser("The user name is not in the correct format", true);
			}
			
			if (!checkPassword(password)) {
				return new UnknownUser("The password is not in the correct format", true);
			}

			// Check against the stored data
			level = StaticUserPassInfo.checkUser(userName, password);
			
			if (level == AuthorizationLevel.NONE) {
				return new UnknownUser("The user information is not correct", true);
			}
			
			return new IdentifiedUser(level);
		} else {
			return passRequestToNext(request);
		}
	}
	
	/**
	 * Checks if the user name has the correct boundaries
	 * @param userName the user name to check
	 * @return if the check was OK
	 */
	private Boolean checkUserName(String userName) {
		// Check length 4 to 10
		if (userName.length() < 4 || userName.length() > 10) {
			return false;
		}
		
		// Check that the user name has only letter and numbers
		for (char c : userName.toCharArray()) {
			if (!(Character.isLetter(c) || Character.isDigit(c))) {
				return false;
			}
		}
		
		return true;
	}
	
	/**
	 * Checks if the password has the correct boundaries
	 * @param password the password to check
	 * @return if the check was OK
	 */
	private Boolean checkPassword(String password) {
		// Check length 6 to 15
		if (password.length() < 6 || password.length() > 15) {
			return false;
		}
		
		// Check number, letter and special char
		Boolean number = false;
		Boolean letter = false;
		Boolean special = false;
		for (char c : password.toCharArray()) {
			if (Character.isLetter(c)) {
				letter = true;
			} else if (Character.isDigit(c)) {
				number = true;
			} else if (!Character.isWhitespace(c)) {
				special = true;
			}
		}
		
		if (!(number && letter && special)) {
			return false;
		}

		return true;
	}
}
